home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises. All rights reserved.
-
- This file is part of Aladdin Ghostscript.
-
- Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
- or distributor accepts any responsibility for the consequences of using it,
- or for whether it serves any particular purpose or works at all, unless he
- or she says so in writing. Refer to the Aladdin Ghostscript Free Public
- License (the "License") for full details.
-
- Every copy of Aladdin Ghostscript must include a copy of the License,
- normally in a plain ASCII text file named PUBLIC. The License grants you
- the right to copy, modify and redistribute Aladdin Ghostscript, but only
- under certain conditions described in the License. Among other things, the
- License requires that the copyright notice and this notice be preserved on
- all copies.
- */
-
- /* gstype1.c */
- /* Adobe Type 1 charstring interpreter */
- #include "math_.h"
- #include "memory_.h"
- #include "gx.h"
- #include "gserrors.h"
- #include "gsstruct.h"
- #include "gxarith.h"
- #include "gxfixed.h"
- #include "gxmatrix.h"
- #include "gxcoord.h"
- #include "gxistate.h"
- #include "gzpath.h"
- #include "gxchar.h"
- #include "gxfont.h"
- #include "gxfont1.h"
- #include "gxtype1.h"
-
- /* Define whether to always do Flex segments as curves. */
- /* This is only an issue because some old Adobe DPS fonts */
- /* seem to violate the Flex specification in a way that requires this. */
- #define ALWAYS_DO_FLEX_AS_CURVE 1
-
- /* ------ Main interpreter ------ */
-
- /* Define a pointer to the charstring interpreter stack. */
- typedef fixed _ss *cs_ptr;
-
- /*
- * Continue interpreting a Type 1 charstring. If str != 0, it is taken as
- * the byte string to interpret. Return 0 on successful completion, <0 on
- * error, or >0 when client intervention is required (or allowed). The int*
- * argument is where the othersubr # is stored for callothersubr.
- */
- private int
- gs_type1_charstring_interpret(gs_type1_state *pcis,
- const gs_const_string *str, int *pindex)
- { gs_font_type1 *pfont = pcis->pfont;
- gs_type1_data *pdata = &pfont->data;
- bool encrypted = pdata->lenIV >= 0;
- gs_op1_state s;
- fixed cstack[ostack_size];
- #define cs0 cstack[0]
- #define ics0 fixed2int_var(cs0)
- #define cs1 cstack[1]
- #define ics1 fixed2int_var(cs1)
- #define cs2 cstack[2]
- #define ics2 fixed2int_var(cs2)
- #define cs3 cstack[3]
- #define ics3 fixed2int_var(cs3)
- #define cs4 cstack[4]
- #define ics4 fixed2int_var(cs4)
- #define cs5 cstack[5]
- #define ics5 fixed2int_var(cs5)
- cs_ptr csp;
- #define clear csp = cstack - 1
- ip_state *ipsp = &pcis->ipstack[pcis->ips_count - 1];
- register const byte *cip;
- register crypt_state state;
- register int c;
- int code = 0;
- fixed ftx = pcis->origin.x, fty = pcis->origin.y;
-
- switch ( pcis->init_done )
- {
- case -1:
- break;
- case 0:
- gs_type1_finish_init(pcis, &s); /* sets sfc, ptx, pty, origin */
- ftx = pcis->origin.x, fty = pcis->origin.y;
- break;
- default /*case 1*/:
- ptx = pcis->position.x;
- pty = pcis->position.y;
- sfc = pcis->fc;
- }
- sppath = pcis->path;
- s.pcis = pcis;
- init_cstack(cstack, csp, pcis);
-
- if ( str == 0 )
- goto cont;
- ipsp->char_string = *str;
- cip = str->data;
- call: state = crypt_charstring_seed;
- if ( encrypted )
- { int skip = pdata->lenIV;
- /* Skip initial random bytes */
- for ( ; skip > 0; ++cip, --skip )
- decrypt_skip_next(*cip, state);
- }
- goto top;
- cont: cip = ipsp->ip;
- state = ipsp->dstate;
- top: for ( ; ; )
- { uint c0 = *cip++;
-
- charstring_next(c0, state, c, encrypted);
- if ( c >= c_num1 )
- {
- /* This is a number, decode it and push it on the stack. */
-
- if ( c < c_pos2_0 )
- { /* 1-byte number */
- decode_push_num1(csp, c);
- }
- else if ( c < cx_num4 )
- { /* 2-byte number */
- decode_push_num2(csp, c, cip, state, encrypted);
- }
- else if ( c == cx_num4 )
- { /* 4-byte number */
- long lw;
-
- decode_num4(lw, cip, state, encrypted);
- *++csp = int2fixed(lw);
- if ( lw != fixed2long(*csp) )
- return_error(gs_error_rangecheck);
- }
- else /* not possible */
- return_error(gs_error_invalidfont);
- pushed: if_debug3('1', "[1]%d: (%d) %f\n",
- (int)(csp - cstack), c, fixed2float(*csp));
- continue;
- }
-
- #ifdef DEBUG
- if ( gs_debug['1'] )
- { static const char *c1names[] =
- { char1_command_names };
- if ( c1names[c] == 0 )
- dprintf2("[1]0x%lx: %02x??\n", (ulong)(cip - 1), c);
- else
- dprintf3("[1]0x%lx: %02x %s\n", (ulong)(cip - 1), c,
- c1names[c]);
- }
- #endif
- switch ( (char_command)c )
- {
- #define cnext clear; goto top
- #define inext goto top
-
- /* Commands with identical functions in Type 1 and Type 2, */
- /* except for 'escape'. */
-
- case c_undef0:
- case c_undef2:
- case c_undef17:
- return_error(gs_error_invalidfont);
- case c_callsubr:
- c = fixed2int_var(*csp) + pdata->subroutineNumberBias;
- code = (*pdata->subr_proc)
- (pfont, c, false, &ipsp[1].char_string);
- if ( code < 0 )
- return_error(code);
- --csp;
- ipsp->ip = cip, ipsp->dstate = state;
- ++ipsp;
- cip = ipsp->char_string.data;
- goto call;
- case c_return:
- --ipsp;
- goto cont;
- case c_undoc15:
- /* See gstype1.h for information on this opcode. */
- cnext;
-
- /* Commands with similar but not identical functions */
- /* in Type 1 and Type 2 charstrings. */
-
- case cx_hstem:
- apply_path_hints(pcis, false);
- type1_hstem(pcis, cs0, cs1);
- cnext;
- case cx_vstem:
- apply_path_hints(pcis, false);
- type1_vstem(pcis, cs0, cs1);
- cnext;
- case cx_vmoveto:
- cs1 = cs0;
- cs0 = 0;
- accum_y(cs1);
- move: /* cs0 = dx, cs1 = dy for hint checking. */
- if ( (pcis->hint_next != 0 || path_is_drawing(sppath)) &&
- pcis->flex_count == flex_max
- )
- apply_path_hints(pcis, true);
- code = gx_path_add_point(sppath, ptx, pty);
- goto cc;
- case cx_rlineto:
- accum_xy(cs0, cs1);
- line: /* cs0 = dx, cs1 = dy for hint checking. */
- code = gx_path_add_line(sppath, ptx, pty);
- cc: if ( code < 0 )
- return code;
- pp: if_debug2('1', "[1]pt=(%g,%g)\n",
- fixed2float(ptx), fixed2float(pty));
- cnext;
- case cx_hlineto:
- accum_x(cs0);
- cs1 = 0;
- goto line;
- case cx_vlineto:
- cs1 = cs0;
- cs0 = 0;
- accum_y(cs1);
- goto line;
- case cx_rrcurveto:
- code = gs_op1_rrcurveto(&s, cs0, cs1, cs2, cs3, cs4, cs5);
- goto cc;
- case cx_endchar:
- if ( pcis->seac_base >= 0 )
- { /* We just finished the accent of a seac. */
- /* Do the base character. */
- gs_const_string bstr;
- int bchar = pcis->seac_base;
- pcis->seac_base = -1;
- /* Restore the coordinate system origin */
- pcis->asb_diff = pcis->adxy.x = pcis->adxy.y = 0;
- sppath->position.x = pcis->position.x = ftx;
- sppath->position.y = pcis->position.y = fty;
- pcis->os_count = 0; /* clear */
- /* Clear the ipstack, in case the accent ended */
- /* inside a subroutine. */
- pcis->ips_count = 1;
- /* Remove any accent hints. */
- reset_stem_hints(pcis);
- /* Ask the caller to provide a new string. */
- code = (*pdata->seac_proc)(pfont, bchar, &bstr);
- if ( code != 0 )
- { *pindex = bchar;
- return code;
- }
- /* Continue with the supplied string. */
- clear;
- ptx = ftx, pty = fty;
- ipsp = &pcis->ipstack[0];
- ipsp->char_string = bstr;
- cip = bstr.data;
- goto call;
- }
- /* This is a real endchar. Handle it below. */
- return gs_type1_endchar(pcis);
- case cx_rmoveto:
- accum_xy(cs0, cs1);
- goto move;
- case cx_hmoveto:
- accum_x(cs0);
- cs1 = 0;
- goto move;
- case cx_vhcurveto:
- { gs_fixed_point pt1, pt2;
- fixed ax0 = sppath->position.x - ptx;
- fixed ay0 = sppath->position.y - pty;
- accum_y(cs0);
- pt1.x = ptx + ax0, pt1.y = pty + ay0;
- accum_xy(cs1, cs2);
- pt2.x = ptx, pt2.y = pty;
- accum_x(cs3);
- code = gx_path_add_curve(sppath, pt1.x, pt1.y, pt2.x, pt2.y, ptx, pty);
- } goto cc;
- case cx_hvcurveto:
- { gs_fixed_point pt1, pt2;
- fixed ax0 = sppath->position.x - ptx;
- fixed ay0 = sppath->position.y - pty;
- accum_x(cs0);
- pt1.x = ptx + ax0, pt1.y = pty + ay0;
- accum_xy(cs1, cs2);
- pt2.x = ptx, pt2.y = pty;
- accum_y(cs3);
- code = gx_path_add_curve(sppath, pt1.x, pt1.y, pt2.x, pt2.y, ptx, pty);
- } goto cc;
-
- /* Commands only recognized in Type 1 charstrings, */
- /* plus 'escape'. */
-
- case c1_closepath:
- code = gs_op1_closepath(&s);
- apply_path_hints(pcis, true);
- goto cc;
- case c1_hsbw:
- gs_type1_sbw(pcis, cs0, fixed_0, cs1, fixed_0);
- rsbw: /* Give the caller the opportunity to intervene. */
- pcis->os_count = 0; /* clear */
- ipsp->ip = cip, ipsp->dstate = state;
- pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
- /* If we aren't in a seac, do nothing else now; */
- /* finish_init will take care of the rest. */
- if ( pcis->init_done < 0 )
- { /* Finish init when we return. */
- pcis->init_done = 0;
- }
- else
- { /* Do accumulate the side bearing now. */
- accum_xy(pcis->lsb.x, pcis->lsb.y);
- pcis->position.x = ptx;
- pcis->position.y = pty;
- }
- return type1_result_sbw;
- case cx_escape:
- charstring_next(*cip, state, c, encrypted); ++cip;
- #ifdef DEBUG
- if ( gs_debug['1'] && c < char1_extended_command_count )
- { static const char *ce1names[] =
- { char1_extended_command_names };
- if ( ce1names[c] == 0 )
- dprintf2("[1]0x%lx: %02x??\n", (ulong)(cip - 1), c);
- else
- dprintf3("[1]0x%lx: %02x %s\n", (ulong)(cip - 1), c,
- ce1names[c]);
- }
- #endif
- switch ( (char1_extended_command)c )
- {
- case ce1_dotsection:
- pcis->dotsection_flag ^=
- (dotsection_in ^ dotsection_out);
- cnext;
- case ce1_vstem3:
- apply_path_hints(pcis, false);
- if ( !pcis->vstem3_set && pcis->fh.use_x_hints )
- { center_vstem(pcis, pcis->lsb.x + cs2, cs3);
- /* Adjust the current point */
- /* (center_vstem handles everything else). */
- ptx += pcis->vs_offset.x;
- pty += pcis->vs_offset.y;
- pcis->vstem3_set = true;
- }
- type1_vstem(pcis, cs0, cs1);
- type1_vstem(pcis, cs2, cs3);
- type1_vstem(pcis, cs4, cs5);
- cnext;
- case ce1_hstem3:
- apply_path_hints(pcis, false);
- type1_hstem(pcis, cs0, cs1);
- type1_hstem(pcis, cs2, cs3);
- type1_hstem(pcis, cs4, cs5);
- cnext;
- case ce1_seac:
- { gs_const_string acstr;
- /* Do the accent now. When it finishes */
- /* (detected in endchar), do the base character. */
- pcis->seac_base = ics3;
- /* Adjust the origin of the coordinate system */
- /* for the accent (endchar puts it back). */
- ptx = ftx, pty = fty;
- pcis->asb_diff = cs0 - pcis->lsb.x;
- pcis->adxy.x = cs1;
- pcis->adxy.y = cs2;
- accum_xy(cs1, cs2);
- sppath->position.x = pcis->position.x = ptx;
- sppath->position.y = pcis->position.y = pty;
- pcis->os_count = 0; /* clear */
- /* Ask the caller to provide a new string. */
- code = (*pdata->seac_proc)(pfont, ics4, &acstr);
- if ( code != 0 )
- { *pindex = ics4;
- return code;
- }
- /* Continue with the supplied string. */
- clear;
- ipsp->char_string = acstr;
- cip = acstr.data;
- goto call;
- }
- case ce1_sbw:
- gs_type1_sbw(pcis, cs0, cs1, cs2, cs3);
- goto rsbw;
- case ce1_div:
- csp[-1] = float2fixed((float)csp[-1] / (float)*csp);
- --csp; goto pushed;
- case ce1_undoc15:
- /* See gstype1.h for information on this opcode. */
- cnext;
- case ce1_callothersubr:
- { int num_results;
- #define fpts pcis->flex_points
- /* We must remember to pop both the othersubr # */
- /* and the argument count off the stack. */
- switch ( *pindex = fixed2int_var(*csp) )
- {
- case 0:
- { /* We have to do something really sleazy */
- /* here, namely, make it look as though */
- /* the rmovetos never really happened, */
- /* because we don't want to interrupt */
- /* the current subpath. */
- gs_fixed_point ept;
- #if defined(DEBUG) || !ALWAYS_DO_FLEX_AS_CURVE
- fixed fheight = csp[-4];
- #endif
- gs_fixed_point hpt;
-
- if ( pcis->flex_count != 8 )
- return_error(gs_error_invalidfont);
- /* Assume the next two opcodes */
- /* are `pop' `pop'. Unfortunately, some */
- /* Monotype fonts put these in a Subr, */
- /* so we can't just look ahead in the */
- /* opcode stream. */
- pcis->ignore_pops = 2;
- csp[-4] = csp[-3] - pcis->asb_diff;
- csp[-3] = csp[-2];
- csp -= 3;
- gx_path_current_point(sppath, &ept);
- gx_path_add_point(sppath, fpts[0].x, fpts[0].y);
- sppath->state_flags = /* <--- sleaze */
- pcis->flex_path_state_flags;
- /* Decide whether to do the flex as a curve. */
- hpt.x = fpts[1].x - fpts[4].x;
- hpt.y = fpts[1].y - fpts[4].y;
- if_debug3('1',
- "[1]flex: d=(%g,%g), height=%g\n",
- fixed2float(hpt.x), fixed2float(hpt.y),
- fixed2float(fheight) / 100);
- #if !ALWAYS_DO_FLEX_AS_CURVE /* See beginning of file. */
- if ( any_abs(hpt.x) + any_abs(hpt.y) <
- fheight / 100
- )
- { /* Do the flex as a line. */
- code = gx_path_add_line(sppath,
- ept.x, ept.y);
- }
- else
- #endif
- { /* Do the flex as a curve. */
- code = gx_path_add_curve(sppath,
- fpts[2].x, fpts[2].y,
- fpts[3].x, fpts[3].y,
- fpts[4].x, fpts[4].y);
- if ( code < 0 )
- return code;
- code = gx_path_add_curve(sppath,
- fpts[5].x, fpts[5].y,
- fpts[6].x, fpts[6].y,
- fpts[7].x, fpts[7].y);
- }
- }
- if ( code < 0 )
- return code;
- pcis->flex_count = flex_max; /* not inside flex */
- inext;
- case 1:
- gx_path_current_point(sppath, &fpts[0]);
- pcis->flex_path_state_flags = /* <--- more sleaze */
- sppath->state_flags;
- pcis->flex_count = 1;
- csp -= 2;
- inext;
- case 2:
- if ( pcis->flex_count >= flex_max )
- return_error(gs_error_invalidfont);
- gx_path_current_point(sppath,
- &fpts[pcis->flex_count++]);
- csp -= 2;
- inext;
- case 3:
- /* Assume the next opcode is a `pop'. */
- /* See above as to why we don't just */
- /* look ahead in the opcode stream. */
- pcis->ignore_pops = 1;
- replace_stem_hints(pcis);
- csp -= 2;
- inext;
- case 14:
- num_results = 1;
- blend: { int num_values = fixed2int_var(csp[-1]);
- int k1 = num_values / num_results - 1;
- int i, j;
- cs_ptr base, deltas;
-
- if ( num_values < num_results ||
- num_values % num_results != 0
- )
- return_error(gs_error_invalidfont);
- base = csp - 1 - num_values;
- deltas = base + num_results - 1;
- for ( j = 0; j < num_results;
- j++, base++, deltas += k1
- )
- for ( i = 1; i <= k1; i++ )
- *base += deltas[i] *
- pdata->WeightVector.values[i];
- csp = base - 1;
- }
- pcis->ignore_pops = num_results;
- inext;
- case 15:
- num_results = 2;
- goto blend;
- case 16:
- num_results = 3;
- goto blend;
- case 17:
- num_results = 4;
- goto blend;
- case 18:
- num_results = 6;
- goto blend;
- }
- }
- #undef fpts
- /* Not a recognized othersubr, */
- /* let the client handle it. */
- { int scount = csp - cstack;
- int n;
- /* Copy the arguments to the caller's stack. */
- if ( scount < 1 || csp[-1] < 0 ||
- csp[-1] > int2fixed(scount - 1)
- )
- return_error(gs_error_invalidfont);
- n = fixed2int_var(csp[-1]);
- code = (*pdata->push_proc)(pfont, csp - (n + 1), n);
- if ( code < 0 )
- return_error(code);
- scount -= n + 1;
- pcis->position.x = ptx;
- pcis->position.y = pty;
- apply_path_hints(pcis, false);
- /* Exit to caller */
- ipsp->ip = cip, ipsp->dstate = state;
- pcis->os_count = scount;
- pcis->ips_count = ipsp - &pcis->ipstack[0] + 1;
- if ( scount )
- memcpy(pcis->ostack, cstack, scount * sizeof(fixed));
- return type1_result_callothersubr;
- }
- case ce1_pop:
- /* Check whether we're ignoring the pops after */
- /* a known othersubr. */
- if ( pcis->ignore_pops != 0 )
- { pcis->ignore_pops--;
- inext;
- }
- ++csp;
- code = (*pdata->pop_proc)(pfont, csp);
- if ( code < 0 )
- return_error(code);
- goto pushed;
- case ce1_setcurrentpoint:
- ptx = ftx, pty = fty;
- cs0 += pcis->adxy.x;
- cs1 += pcis->adxy.y;
- accum_xy(cs0, cs1);
- goto pp;
- default:
- return_error(gs_error_invalidfont);
- }
- /*NOTREACHED*/
-
- /* Fill up the dispatch up to 32. */
-
- case_c1_undefs:
- default: /* pacify compiler */
- return_error(gs_error_invalidfont);
- }
- }
- }
-
- /* Register the interpreter. */
- void
- gs_gstype1_init(gs_memory_t *mem)
- { gs_charstring_interpreter[1] = gs_type1_charstring_interpret;
- }
-